﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace zUfDsl.Ext
{
    public class SuperGridSum : System.Windows.Forms.DataGridView
    {
        #region 3.初始化变量并注册DataGridView相关事件,增加效果处理
        private string sumCellFormat = "N2";           //合计单元格格式化字符串
        private int sumRowHeight = 30;                 //合计行高
        private DataGridView dgvSum = null;         //合计行
        private VScrollBar vScrollBar = null;          //垂直滚动条
        private HScrollBar hScrollBar = null;          //水平滚动条
        private bool initSourceGriding = false;        //指示是否正在进行初始grid
        private DockStyle dock;                        //Dock

        private int dgvSourceMaxHeight = 0;           //dgvSource最大高度
        private int dgvSourceMaxWidth = 0;             //dgvSource最大宽度


        /// <summary>
        /// 初始化
        /// </summary>
        public SuperGridSum()
        {
            base.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.ColumnWidthChanged += new DataGridViewColumnEventHandler(thisColumnWidthChanged);
            //this.DataSourceChanged += new EventHandler(thisDataSourceChanged);
            this.RowHeadersWidthChanged += new EventHandler(thisRowHeadersWidthChanged);
            this.MouseWheel += new MouseEventHandler(dgvSourceMouseWheel);
            this.Sorted += new System.EventHandler(this.SuperGridSumSorted);

        }
        #endregion




        #region 4.禁用DataGridView 默认的滚动条,改为手动添加横向滚动条及纵向滚动条.并将其添加到和DateGridView 相同的父控件上,示例代码如下
        /// <summary>
        /// 初始化合计行
        /// </summary>
        public void InitSum()
        {
            if (this.Parent == null)
            {
                return;
            }

            #region 初始化合计的DataGridView;
            dgvSum = new DataGridView()
            {
                RowHeadersVisible = false,
                BackgroundColor = this.BackgroundColor,
                ColumnHeadersVisible = false,
                AllowUserToResizeColumns = false,
                AllowUserToResizeRows = false,
                ScrollBars = System.Windows.Forms.ScrollBars.None,
                Height = sumRowHeight,
                AllowUserToAddRows = false,
                RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing,
                ReadOnly = true,
                BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle,
                Font = new Font("宋体", 10, FontStyle.Bold),                
            };
            dgvSum.RowTemplate.Height = sumRowHeight;
            dgvSum.DefaultCellStyle.SelectionBackColor = dgvSum.DefaultCellStyle.BackColor;
            dgvSum.DefaultCellStyle.SelectionForeColor = dgvSum.DefaultCellStyle.ForeColor;            
            this.Parent.Controls.Add(dgvSum);
            #endregion

            #region 初始化滚动条
            //滚动条
            vScrollBar = new VScrollBar() { Width = 15, Height = this.Height, Left = this.Left + this.Width, Top = this.Top };
            hScrollBar = new HScrollBar() { Width = this.Width, Height = 15, Left = this.Left, Top = this.Top + this.Height };
            vScrollBar.Scroll += new ScrollEventHandler(vScrollBarScroll);
            hScrollBar.Scroll += new ScrollEventHandler(hScrollBarScroll);
            this.ScrollBars = ScrollBars.None;         //禁用dgv默认滚动条
            this.Parent.Controls.Add(vScrollBar);
            this.Parent.Controls.Add(hScrollBar);
            ReInitDGVSum();
            ResizeDGVSum();
            ResizeHScrollBar();
            ResizeVScrollBar();

            //注册滚动条事件已代替dgv默认的滚动条
            this.SizeChanged += (s, e) =>
            {
                if (!initSourceGriding)
                {
                    InitScrollWithSourceGrid();
                    this.Update();
                }
            };
            #endregion 
        }

        public void SetSum(System.Data.DataTable dt)
        {
            if(dgvSum==null) { InitSum(); }
            dgvSum.DataSource = dt;           
        }


        #endregion

        private void ReInitDGVSum()
        {
            dgvSum.Columns.Clear();
            for (int j = 0; j < this.Columns.Count; j++)
            {
                var t = this.Columns[j];
                var tmpc = new DataGridViewTextBoxColumn()
                { Visible = t.Visible, Name = t.Name, DataPropertyName = t.DataPropertyName, HeaderText = t.HeaderText, Width = t.Width, Frozen = t.Frozen, DisplayIndex = t.DisplayIndex };
                tmpc.DefaultCellStyle.Alignment = t.DefaultCellStyle.Alignment;
                if (t.DefaultCellStyle.Format.ObjToString().Length > 0)
                {
                    tmpc.DefaultCellStyle.Format = t.DefaultCellStyle.Format;
                }
                dgvSum.Columns.Add(tmpc);
            }
        }

        #region 调整datagridview的位置
        /// <summary>
        /// 调整datagridview的位置
        /// </summary>
        private void ResizeDGVSum()
        {            
            dgvSum.Location = new Point(this.Location.X, this.Location.Y + this.Height - 1);
            dgvSum.Width = this.Width;
            dgvSum.Visible = true;
            dgvSum.BringToFront();
        }

        #endregion 

        #region 调整水平滚动条的位置
        /// <summary>
        /// 调整水平滚动条的位置
        /// </summary>
        private void ResizeHScrollBar()
        {
            if (dgvSum == null || hScrollBar == null) { return; }


            //需要展示水平滚动条
            if (this.DisplayedColumnCount(true) < this.Columns.Count)
            {
                hScrollBar.Location = new Point(this.Location.X, this.Location.Y + this.Height + dgvSum.Height);
                hScrollBar.Width = this.Width;
                hScrollBar.Visible = true;
                hScrollBar.BringToFront();
                hScrollBar.Minimum = 0;

                int icolscount = 0;
                int icolswidth = 0;
                foreach (DataGridViewColumn col in this.Columns)
                {
                    if (!col.Visible)
                    {
                        continue;
                    }
                    icolswidth += col.Width;
                    icolscount++;
                }
                var agvcolwidth = icolswidth / icolscount;

                hScrollBar.SmallChange = agvcolwidth;
                hScrollBar.LargeChange = agvcolwidth * 2;
                hScrollBar.Maximum = icolswidth;
            }
            else
            {
                hScrollBar.Visible = false;
            }
        }
        #endregion

        #region 调整垂直滚动条的位置
        /// <summary>
        /// 调整垂直滚动条的位置
        /// </summary>
        private void ResizeVScrollBar()
        {
            if (dgvSum == null || vScrollBar == null) { return; }

            #region 验证是否需要显示纵向滚动条

            var dgvSourceDisplayedRowCount = this.DisplayedRowCount(false);     //最多显示行数

            if (dgvSourceDisplayedRowCount >= this.Rows.Count)
            {
                //不需要展示垂直滚动条
                vScrollBar.Visible = false;
            }
            else
            {
                //需要展示垂直滚动条
                vScrollBar.Visible = true;
                int avgheight = 20;
                if (this.Rows.Count > 0)
                {
                    avgheight = (this.Rows[0].Height - 3);
                }
                this.Width = this.Width - vScrollBar.Width;
                vScrollBar.Height = this.Height + dgvSum.Height;
                vScrollBar.Location = new Point(this.Location.X + this.Width, this.Location.Y);
                vScrollBar.Maximum = (this.Rows.Count - dgvSourceDisplayedRowCount + 2) * avgheight;
                vScrollBar.Minimum = 0;
                vScrollBar.SmallChange = avgheight;
                vScrollBar.LargeChange = avgheight * 2;
                vScrollBar.BringToFront();
            }
            #endregion

        }
        #endregion


        #region 5.根据数据量确定是否需要展示横向及纵向滚动条,同时确定合计行
        /// <summary>
        /// 根据源Grid设置是否需展示滚动条
        /// </summary>
        private void InitScrollWithSourceGrid()
        {
            if (initSourceGriding || this.Parent == null)
            {
                return;
            }
            initSourceGriding = true;
            if (dock == DockStyle.Fill)
            {
                this.Height = Parent.Height;
                this.Width = Parent.Width;
                this.Location = new Point(0, 0);
            }
            dgvSourceMaxHeight = this.Height;           //dgvSource最大高度
            dgvSourceMaxWidth = this.Width;             //dgvSource最大宽度


            dgvSourceMaxHeight -= sumRowHeight;
            if (dgvSourceMaxHeight < RowHeight * 2)
            {
                initSourceGriding = false;
                return;
            }
            ResizeDGVSum();
            ResizeHScrollBar();
            ResizeVScrollBar();
             initSourceGriding = false;
        }

        #endregion

        #region 6.处理滚动条事件,同步作用于两个DataGridView
        /// <summary>
        /// DataGridView 列总宽.用于确定横向滚动条滚动值
        /// </summary>
        private int ColsWidth
        {
            get
            {
                int width = 0;
                foreach (DataGridViewColumn col in this.Columns)
                {
                    if (!col.Visible)
                    {
                        continue;
                    }
                    width += col.Width;
                }
                return width;
            }
        }



        /// <summary>
        /// 每行高度.用于确定纵向滚动条滚动值
        /// </summary>
        private int RowHeight
        {
            get
            {
                int height = 20;
                if (this.Rows.Count > 0)
                {
                    height = (this.Rows[0].Height - 3);
                }
                return height;
            }
        }

        /// <summary>
        /// 处理纵向滚动条事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void vScrollBarScroll(object sender, ScrollEventArgs e)
        {
            if (this.Rows.Count == 0) { return; }
            this.FirstDisplayedScrollingRowIndex = e.NewValue / RowHeight;
        }

        /// <summary>
        /// 处理横向滚动条事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void hScrollBarScroll(object sender, ScrollEventArgs e)
        {
            int value = e.NewValue;
            this.HorizontalScrollingOffset = value;

            if (dgvSum != null)
            {
                dgvSum.HorizontalScrollingOffset = value;
            }
        }

        /// <summary>
        /// 处理源dgv鼠标滚轮滚动事件,同步带动横向滚动条及纵向滚动条
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvSourceMouseWheel(object sender, MouseEventArgs e)
        {
            if (vScrollBar==null || !vScrollBar.Visible) return;

            if ((vScrollBar.Value - RowHeight) < 0 && e.Delta > 0)
            {
                vScrollBar.Value = vScrollBar.Minimum;
            }
            else if ((vScrollBar.Value + RowHeight * 2) > vScrollBar.Maximum && e.Delta < 0)
            {
                vScrollBar.Value = vScrollBar.Maximum;
            }
            else
            {
                vScrollBar.Value -= Convert.ToInt32((e.Delta / Math.Abs(e.Delta))) * RowHeight;
            }
            this.FirstDisplayedScrollingRowIndex = vScrollBar.Value / RowHeight;
        }
        #endregion 


        #region 7.拖动列宽改变的时候,同步更新合计行的列宽
        private void thisColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
        {
            if (dgvSum != null)
            {
                //for (int j = 0; j < this.Columns.Count; j++)
                //{
                //    var t = this.Columns[j];
                //    if (t.Width != dgvSum.Columns[j].Width)
                //    {
                //        dgvSum.Columns[j].Width = t.Width;
                //    }
                //}
                dgvSum.Columns[e.Column.Index].Width = e.Column.Width;
                this.HorizontalScrollingOffset = hScrollBar.Value;
                dgvSum.HorizontalScrollingOffset = hScrollBar.Value;
            }
        }

        private void thisRowHeadersWidthChanged(object sender, EventArgs e)
        {
            if (dgvSum != null)
            {
                //for (int j = 0; j < this.Columns.Count; j++)
                //{
                //    var t = this.Columns[j];
                //    if (t.Width != dgvSum.Columns[j].Width)
                //    {
                //        dgvSum.Columns[j].Width = t.Width;
                //    }
                //}
                dgvSum.RowHeadersWidth = this.RowHeadersWidth - 1;
            }
        }
        #endregion

        #region 根据设置的需要合计列,自动合计数据
        /// <summary>
        /// 需要添加合计的datagridviewrow 列名称
        /// </summary>
        [Description("获取或设置需要用于求和的列名")]
        public string[] SumColumns
        {
            get;
            set;
        }

        /// <summary>
        /// 合计数据
        /// </summary>
        public void SumData()
        {
            if (this.Columns.Count <= 0)
            {
                return;
            }
            if (dgvSum == null) { return; }

            if (dgvSum.Columns.Count != this.Columns.Count)
            {
                dgvSum.Columns.Clear();
                for (int j = 0; j < this.Columns.Count; j++)
                {
                    var t = this.Columns[j];
                    dgvSum.Columns.Add(t.HeaderText, t.HeaderText);
                }
                //AddDgvSumRowColumns();
            }

            if (dgvSum.Rows.Count != 1)
            {
                dgvSum.Rows.Clear();
                dgvSum.Rows.Add(1);
            }

            if (this.Rows.Count <= 0 || SumColumns == null || SumColumns.Length == 0)
            {
                return;
            }

            var sumRowDataDic = new Dictionary<int, decimal>();

            #region 按设置的需要合计的列求和
            Array.ForEach(SumColumns, col =>
            {
                if (!dgvSum.Columns.Contains(col))
                {
                    return;
                }
                var tempSumVal = 0m;
                var colIndex = dgvSum.Columns[col].Index;
                for (int i = 0; i < this.Rows.Count; i++)
                {
                    if (this[colIndex, i].Value == null)
                    {
                        continue;
                    }

                    var tempVal = 0m;
                    try
                    {
                        tempVal = (decimal)Convert.ChangeType(this[colIndex, i].Value, typeof(decimal));
                    }
                    catch { }
                    tempSumVal += tempVal;
                }
                sumRowDataDic[colIndex] = tempSumVal;
            });
            #endregion

            if (sumRowDataDic.Count > 0)
            {
                sumRowDataDic.Keys.ToList().ForEach(colIndex =>
                {
                    dgvSum[colIndex, 0].Value = sumRowDataDic[colIndex];
                });
            }
        }

        /// <summary>
        /// 获取合计行
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public DataGridViewRow SumRow
        {
            get
            {
                return (dgvSum != null && dgvSum.Rows.Count > 0) ? dgvSum.Rows[0] : null;
            }
        }
        #endregion

        #region 9.当数据源改变,重新计算合计,与合计行列头重绘
        private void thisDataSourceChanged(object sender, EventArgs e)
        {
            SumData();
        }

        /// <summary>
        /// 绘制合计行行头
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        //private void dgvSumRowRowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        //{
        //    var rectangle = new Rectangle(e.RowBounds.Location.X + 1, e.RowBounds.Location.Y + 1,
        //        dgvSumRow.RowHeadersWidth - 3, e.RowBounds.Height - 3);

        //    e.Graphics.FillRectangle(new SolidBrush(dgvSumRow.RowHeadersDefaultCellStyle.BackColor), rectangle);

        //    TextRenderer.DrawText(e.Graphics, "合计",
        //        dgvSumRow.RowHeadersDefaultCellStyle.Font,
        //        rectangle,
        //        dgvSumRow.RowHeadersDefaultCellStyle.ForeColor,
        //        TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
        //}
        #endregion

        #region 10.为了便于在设计器中使用,重写部分属性,并禁用可能影响展示效果的属性,同时增加上新的属性设置.

        /// <summary>
        /// 获取或设置Dock,该属性已被重新
        /// </summary>
        [Description("获取或设置Dock,该属性已被重写")]
        public new DockStyle Dock
        {
            get { return dock; }
            set
            {
                dock = value;
                if (value == DockStyle.Fill)
                {
                    if (Parent != null)
                    {
                        this.Size = new Size(Parent.Width, Parent.Height);
                        this.Location = new Point(0, 0);
                    }
                    this.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
                }
                else
                {
                    this.Height = Parent.Height - 20;
                    this.Width = Parent.Width - 20;
                }
            }
        }

        /// <summary>
        /// BorderStyle属性已被重写,该值固定为None,设置无效
        /// </summary>
        [Description("BorderStyle属性已被重写,该值固定为None,设置无效")]
        public new BorderStyle BorderStyle
        {
            get { return System.Windows.Forms.BorderStyle.None; }
            set { }
        }

        /// <summary>
        /// 获取或设置合计行单元格格式化字符串1
        /// </summary>
        [Description("获取或设置合计行单元格格式化字符串2")]
        public string SumRowCellFormat
        {
            get { return sumCellFormat; }
            set { sumCellFormat = value; }
        }
        #endregion

        private void InitializeComponent()
        {
            ((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
            this.SuspendLayout();
            // 
            // SuperGridSum
            // 
            this.RowTemplate.Height = 23;
            ((System.ComponentModel.ISupportInitialize)(this)).EndInit();
            this.ResumeLayout(false);

        }

        private void SuperGridSumSorted(object sender, EventArgs e)
        {
            if (hScrollBar == null) { return; }
            this.HorizontalScrollingOffset = hScrollBar.Value;
            dgvSum.HorizontalScrollingOffset = hScrollBar.Value;
        }
    }
}
